package com.xyq.system.service.exam;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.xyq.common.core.constants.ExamConstants;
import com.xyq.common.core.domain.Result;
import com.xyq.common.core.enums.ResultCode;
import com.xyq.common.core.exception.ServiceException;
import com.xyq.system.domain.exam.Exam;
import com.xyq.system.domain.exam.ExamQuestion;
import com.xyq.system.domain.exam.dto.*;
import com.xyq.system.domain.exam.vo.ExamQuestionListVO;
import com.xyq.system.domain.exam.vo.ExamVO;
import com.xyq.system.domain.question.Question;
import com.xyq.system.manager.ExamCacheManager;
import com.xyq.system.mapper.exam.ExamMapper;
import com.xyq.system.mapper.exam.ExamQuestionMapper;
import com.xyq.system.mapper.question.QuestionMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;

@Service
public class ExamServiceImpl extends ServiceImpl<ExamQuestionMapper ,ExamQuestion > implements ExamService{
    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private ExamMapper examMapper;

    @Autowired
    private  ExamQuestionMapper examQuestionMapper ;

    @Autowired
    private ExamCacheManager examCacheManager;

    @Override
    public List<ExamVO> list(ExamDTO examDTO) {
        // 加入这条语句就足够可以实现 分页查询功能
        PageHelper.startPage(examDTO.getPageNum() , examDTO.getPageSize());
        return  examMapper.selectExamList(examDTO) ;
    }

    @Override
    public Long add(ExamAddDTO examAddDTO) {
         // 竞赛名称不能重复
        List<Exam> exams = examMapper.selectList(new LambdaQueryWrapper<Exam>().eq(Exam::getTitle, examAddDTO.getTitle()));
         if(CollectionUtil.isNotEmpty(exams)){
             throw new ServiceException(ResultCode.FAILED_ALREADY_EXISTS);
         }
        // 判断竞赛的 参数是否合法
        // 精神的开始时间不能小于当前时间
       if(examAddDTO.getStartTime().isBefore(LocalDateTime.now())){
           throw new ServiceException(ResultCode.EXAM_START_TIME_ERROR);
       }
       // 竞赛的结束时间不能早于开始时间
       if(examAddDTO.getStartTime().isAfter(examAddDTO.getEndTime())){
           throw new ServiceException(ResultCode.EXAM_END_TIME_ERROR) ;
       }

        Exam exam = new Exam() ;
        // 复制 参数给他
        BeanUtil.copyProperties(examAddDTO , exam);
         int  result =  examMapper.insert(exam) ;
            if(result <= 0){
                return  0L ;
            }
       return exam.getExamId() ;
    }

    @Override
    public boolean addQuestion(ExamQuestionAddDTO examQuestionAddDTO) {
        // 判断竞赛是否存在
        Exam exam = getExam(examQuestionAddDTO.getExamId());
        // 判断竞赛是否已经发布
        isPublish(exam);
        // 看下 有没有题目
        LinkedHashSet<Long> questions = examQuestionAddDTO.getQuestionIdSet();
        if(CollectionUtil.isEmpty(examQuestionAddDTO.getQuestionIdSet()) || examQuestionAddDTO.getQuestionIdSet().size() <= 0){
            throw new ServiceException(ResultCode.QUESTIONS_NOT_EXISTS);
        }

        // 查询一些题目是否正确
        // 题目的排序顺序
        int num = 1 ;
        // 对一组题目的统一查找
        List<Question> questions1 = questionMapper.selectBatchIds(questions);
         if(CollectionUtil.isEmpty(questions1) || questions1.size() < questions.size()){
             // 如果添加的题目不存在     如果question1为空 或者 查出来的个数少于 请求的个数 , 都表示有题目id不正确
             throw new ServiceException(ResultCode.QUESTION_NOT_EXISTS) ;
         }
  
         // 查看竞赛列表里是否已经有 题目了

          List<ExamQuestion> list = new ArrayList<>() ;
        for(long id : questions){
            // 判断id是题目是否已经存在
            List<ExamQuestion> examQuestions = examQuestionMapper.selectList(
                    new LambdaQueryWrapper<ExamQuestion>()
                            .eq(ExamQuestion::getQuestionId, id).eq(ExamQuestion::getExamId,exam.getExamId()));
            if(CollectionUtil.isNotEmpty(examQuestions)){
                throw  new ServiceException(ResultCode.EXAM_QUESTION_ALREADY_EXISTS);
            }

            ExamQuestion examQuestion = new ExamQuestion() ;
            examQuestion.setExamId(exam.getExamId());
            examQuestion.setQuestionId(id);
            examQuestion.setQuestionOrder(num++);   // 题目之间的顺序
           list.add(examQuestion) ;
        }

        // 对竞赛题目进行统一添加
        return saveBatch(list) ;    // 返回批量插入响应

    }

    @Override
    public Result getExamDetailById(Long examId) {
        if(examId == null || examId <=0){
            return Result.fail(ResultCode.FAILED_PARAMS_VALIDATE) ;
        }
        Exam exam = getExam(examId) ;
        ExamQuestionListVO examQuestionListVO = new ExamQuestionListVO() ;
        examQuestionListVO.setExamId(examId);
        examQuestionListVO.setTitle(exam.getTitle());
        examQuestionListVO.setStartTime(exam.getStartTime());
        examQuestionListVO.setEndTime(exam.getEndTime());
        List<Question> list =  examQuestionMapper.selectQuestionListById(examId) ;
        examQuestionListVO.setExamQuestionList(list);
        return Result.success(examQuestionListVO);
    }
     // 编辑竞赛信息
    @Override
    public int editExam(ExamEditDTO examEditDTO) {
        Exam exam = getExam(examEditDTO.getExamId());
        // 判断竞赛是否已经发布
        isPublish(exam);

        exam.setTitle(examEditDTO.getTitle());
        exam.setStartTime(examEditDTO.getStartTime());
        exam.setEndTime(examEditDTO.getEndTime());
        // 更新竞赛信息
        return examMapper.updateById(exam);
    }

    // 删除竞赛
    @Override
    public int deleteExam(Long examId) {
        if(examId == null){
            throw new ServiceException(ResultCode.FAILED_PARAMS_VALIDATE);
        }
        Exam exam = getExam(examId);
        isPublish(exam);
        // 判断竞赛是否已发布或已经发布的竞赛不能删除

        return examMapper.deleteById(examId);
    }
 // 删除竞赛里的题目
    @Override
    public int deleteExamQuestion(ExamQuestionDeleteDTO examQuestionDeleteDTO) {
         // 竞赛是否已经发布 , 已经发布的竞赛不能操作
        Exam exam = getExam(examQuestionDeleteDTO.getExamId()) ;
        // 如果竞赛已经发布就不能操作
        isPublish(exam);
        // 拼单竞赛里是否存在题目
        List<ExamQuestion> examQuestions = examQuestionMapper.selectList(
                new LambdaQueryWrapper<ExamQuestion>()
                        .eq(ExamQuestion::getQuestionId,examQuestionDeleteDTO.getQuestionId()).
                        eq(ExamQuestion::getExamId,examQuestionDeleteDTO.getExamId()));
        if(CollectionUtil.isEmpty(examQuestions)){
            throw  new ServiceException(ResultCode.FAILED_NOT_EXISTS);
        }
        // 如果存在则删除
        return examQuestionMapper.deleteById(examQuestions.get(0).getExamQuestionId());
    }
      // 发布竞赛
    @Override
    public int publishExam(Long examId) {
        Exam exam = getExam(examId);
        // 在发布竞赛前一个先判断 , 竞赛是否已经结束, 已经结束的竞赛不应该发布
        // 已经开始的竞赛也不应该发布
         isStartOrEnd(exam) ;
         // 如果竞赛里没有题目也不允许发布
        List<ExamQuestion> examQuestions = examQuestionMapper.
                selectList(new LambdaQueryWrapper<ExamQuestion>().eq(ExamQuestion::getExamId, examId));
        if(CollectionUtil.isEmpty(examQuestions)){
           throw new ServiceException(ResultCode.QUESTIONS_NOT_EXISTS);
        }
        exam.setStatus(ExamConstants.EXAM_PUBLISH);

        // 将竞赛信息存储到redis里
        examCacheManager.addCache(exam);

        return examMapper.updateById(exam);
    }

    //  撤销发布竞赛
    @Override
    public int cancelPublishExam(Long examId) {
        Exam exam = getExam(examId);

        // 在撤销竞赛前一个先判断 , 竞赛是否已经结束, 已经结束的竞赛不应该撤销或者 是否已经开始
        isStartOrEnd(exam);
        exam.setStatus(ExamConstants.EXAM_NO_PUBLISH);

        // 撤销发布的时候 应该从redis里删除竞赛
        examCacheManager.deleteCache(exam);

        return examMapper.updateById(exam);
    }

    // 判断竞赛是否存在
    private Exam getExam(Long examId ) {
        Exam exam = examMapper.selectById(examId);
        if(exam == null){
            throw new ServiceException(ResultCode.EXAM_NOT_EXISTS);
        }
        return exam;
    }
    // 判断竞赛是否已经开始 或者已经结束
    private void isStartOrEnd(Exam exam){
        if(exam.getStartTime().isBefore(LocalDateTime.now())){
            throw new ServiceException(ResultCode.EXAM_IS_START);
        }else   if(exam.getEndTime().isBefore(LocalDateTime.now())){
            // 竞赛已经结束
            throw new ServiceException(ResultCode.EXAM_IS_FINISH);
        }
    }
    // 判断是否已经发布
    private void isPublish(Exam exam){
        if(exam.getStatus().equals(ExamConstants.EXAM_PUBLISH)){
            throw new ServiceException(ResultCode.EXAM_IS_PUBLISH);
        }
    }

}
